/*
 * @author Chris
 * @since 2023/1/27 22:08
 *
 * @brief    The project will ...
 *
 * @note     ...
 *
 * @warning  Do not to ...
 *
 * Change Logs:
 *   Date           Author       Notes
 *   2023/1/27     Chris        the first version
 */

#include "reg51.h"

#define _nop_() __asm nop __endasm

#define I2CDelay() _nop_();_nop_();_nop_();_nop_();

#define I2C_SCL P3_7
#define I2C_SDA P3_6

extern void InitLcd1602();

extern void Lcd1602ShowStr(unsigned char x, unsigned char y, unsigned char *buf, unsigned char len);

__bit I2CSelectAddress(unsigned char addr);

int main() {
    InitLcd1602();

    __bit ack;
    unsigned char str[10];
    ack = I2CSelectAddress(0x50);
    str[0] = '5';
    str[1] = '0';
    str[2] = ':';
    str[3] = (unsigned char) ack + '0';
    Lcd1602ShowStr(0, 0, str, 4);

    ack = I2CSelectAddress(0x62);
    str[0] = '6';
    str[1] = '2';
    str[2] = ':';
    str[3] = (unsigned char) ack + '0';
    Lcd1602ShowStr(0, 1, str, 4);

    while (1);
}

void I2CStart() {
    I2C_SDA = 1;
    I2C_SCL = 1;
    I2CDelay();
    I2C_SDA = 0;
    I2CDelay();
}

__bit I2CWrite(unsigned char dat) {
    I2C_SCL = 0;
    I2CDelay();

    for (unsigned char mask = 0x80; mask != 0; mask >>= 1) {
        I2C_SDA = (mask & dat) == 0 ? 0 : 1;
        I2CDelay();
        I2C_SCL = 1;
        I2CDelay();
        I2C_SCL = 0;
    }

    // 读取 ACK
    I2C_SDA = 1;
    I2CDelay();
    I2C_SCL = 1;
    __bit ack = I2C_SDA;
    I2CDelay();
    I2C_SCL = 0;
    return ack;
}

void I2CStop() {
    I2C_SCL = 0;
    I2C_SDA = 0;
    I2CDelay();
    I2C_SCL = 1;
    I2CDelay();
    I2C_SDA = 1;
    I2CDelay();
}

__bit I2CSelectAddress(unsigned char addr) {
    I2CStart(); // 起始信号：在 SCL 为高电平时，SDA 下降沿
    __bit ack = I2CWrite(addr << 1);// SCL 低电平时改变 SDA，SCL 一为高电平时保持 SDA
    I2CStop();  // 停止信号：拉低 SCL 和 SDA，然后在 SCL 为高电平时，SDA 上升沿
    return ack;
}